//
//  OPRepository.m
//  Pods
//
//  Created by lingen on 16/3/21.
//
//

#import "OPFRepository.h"
#import "FMDB.h"
#import "OPFTableProtocol.h"
#import "OPFTable.h"
#import "FMDatabaseQueue+OPH.h"
#import <CocoaLumberjack/CocoaLumberjack.h>
#import <FMDB/FMDatabase.h>

const static int DB_MONITOR_TIME = 200;

static const DDLogLevel ddLogLevel = DDLogLevelVerbose;

static NSString* DB_THREAD_NAME = @"PANDA DB Thread";

@interface OPFRepository()

/*
 *数据库路径
 */
@property (nonatomic,strong) NSString* dbPath;

/*
 * 表格定义模型
 */
@property (nonatomic,strong) NSArray* tables;

/*
 *数据库FMDB
 */
@property (nonatomic,strong) FMDatabaseQueue* dbQueue;

/*
 *数据库队列
 */
@property (nonatomic,strong) dispatch_queue_t threadQueue;

/*
 *数据库TAG
 */
@property (nonatomic,strong) NSString* tag;

/*
 *版本号
 */
@property (nonatomic,assign) int version;

@end

//创建版本控制的语句
static NSString* CREATE_VERSION_TABLE = @"CREATE TABLE PANDA_VERSION_ (VALUE_ INT NOT NULL)";

//初始化版本控制的语句
static NSString* INIT_VERSION_TABLE_CONTENT = @"INSERT INTO PANDA_VERSION_ (VALUE_) values (%@)";

//查询当前的版本号
static NSString* QUERY_CURRENT_VERSION = @"SELECT VALUE_ FROM PANDA_VERSION_ LIMIT 1";

//更新版本SQL
static NSString* UPDATE_VERSION = @"UPDATE PANDA_VERSION_ SET VALUE_ = %d";

@implementation OPFRepository

/*
 *初始化数据库路径以及表格对象
 */
-(instancetype)initWith:(NSString*) dbPath tables:(NSArray*)tables version:(int)version encrypt:(NSString*)encrypt{
    if (self = [super init]) {
        _dbPath = dbPath;
        _tables = tables;
        _version = version;
        _tag = [[NSUUID UUID] UUIDString];
         _encrypt = encrypt;
        NSString *threadName = [NSString stringWithFormat:@"db.panda.%@",_tag];
        _threadQueue = dispatch_queue_create([threadName UTF8String], NULL);
        [self p_initRepository];
        return self;
    }
    return nil;
}

/*
 *此方法用于初始化数据库及表格
 */
-(void)p_initRepository{
    
     if (_dbQueue) {
          [self close];
     }
    BOOL dbFileExists = [[NSFileManager defaultManager] fileExistsAtPath:_dbPath];
    _dbQueue = [FMDatabaseQueue databaseQueueWithPath:_dbPath];
    
     [self encryptIfNesscery];
     
    if (dbFileExists) {
        [self p_updateDB];
        //如果路径都不存在，则表明表格不存在，需要重新创建表格
    }else{
        [self p_initDB];
    }
}

-(void)encryptIfNesscery{
     if (_encrypt) {
          [_dbQueue inDatabase:^(FMDatabase *db) {
              [db setKey:self->_encrypt];
          }];
     }
}
/*
 *数据库初始化操作
 */
-(void)p_initDB{
     if (!_threadQueue) {
          return;
     }
     dispatch_sync(_threadQueue, ^{


         [_dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
              //创建版本号相关的表
              BOOL success = [db executeStatements:CREATE_VERSION_TABLE];
              if (success) {
                   NSLog(@"Panda Success：初始化数据库，创建版本号表成功");
              }else{
                   NSLog(@"Panda Error：初始化数据库，创建版本号表失败");
                   *rollback = YES;
              }
              //初始化版本号
              success = [db executeStatements:[NSString stringWithFormat:INIT_VERSION_TABLE_CONTENT,@(_version)]];
              
              if (success) {
                   NSLog(@"Panda Success：初始化版本号表成功");
              }else{
                   NSLog(@"Panda Error：初始化版本号表失败");
                   *rollback = YES;
              }
              NSMutableArray *sqls = [[NSMutableArray alloc] init];
              //初始化所有的表
              for (Class tableProtocolClass in _tables) {
                   //进行数据库层的初始化操作
                   if ([tableProtocolClass conformsToProtocol:@protocol(OPFTableProtocol)]) {
                        OPFTable* opfTable = [tableProtocolClass performSelector:@selector(createTable)];
                        //获取建表语句
                        [sqls addObject:[opfTable createTableSQL]];
                        
                        NSString* indexSQL = [opfTable createIndexSQL];
                        if (indexSQL && ![indexSQL isEqualToString:@""]) {
                             //获取创建索引的语句
                             [sqls addObject:indexSQL];
                        }
                   }
              }
              
              for (NSString* sql in sqls) {
                   BOOL success =  [db executeStatements:sql];
                   if (success) {
                        NSLog(@"Panda Success:表初始化成功:%@",sql);
                   }else{
                        [self p_strictMode:[db lastError]];
                        NSLog(@"Panda Error:表初始化失败%@",sql);
                        *rollback = YES;
                   }
              }
         }];
     });
}

-(void)close{
     dispatch_sync(_threadQueue, ^{
          [_dbQueue close];
          _dbQueue = nil;
     });
}

/*
 *数据库更新操作
 */
-(void)p_updateDB{
    __block int dbVersion = 0;
     if (!_dbQueue) {
          return;
     }
    dispatch_sync(_threadQueue, ^{
        
        [_dbQueue inDatabase:^(FMDatabase *db) {
            FMResultSet *rs = [db executeQuery:QUERY_CURRENT_VERSION];
             if (rs.next) {
                  dbVersion = [rs intForColumn:@"VALUE_"];
             }
            if (rs) {
                [rs close];
            }
        }];
        
        NSMutableArray *sqls = [[NSMutableArray alloc] init];
        
        //对于更新，也需要创建不存在的表
        for (Class tableProtocolClass in _tables) {
            //进行数据库层的初始化操作
            if ([tableProtocolClass conformsToProtocol:@protocol(OPFTableProtocol)]) {
                OPFTable* opfTable = [tableProtocolClass performSelector:@selector(createTable)];
                 
                 __block BOOL tableExist = NO;
                 [_dbQueue inDatabase:^(FMDatabase *db) {
                      NSString* sql = @"SELECT * FROM sqlite_master WHERE type='table' AND name=?";
                      FMResultSet *rs  = [db executeQuery:sql withArgumentsInArray:@[opfTable.tableName]];
                      if (rs.next) {
                           tableExist = YES;
                      }else{
                           tableExist = NO;
                      }
                      if (rs) {
                           [rs close];
                      }
                 }];
   
               if (!tableExist) {
                    //获取建表语句
                    [sqls addObject:[opfTable createTableSQL]];
                     NSString* indexSQL = [opfTable createIndexSQL];
                     if (indexSQL && ![indexSQL isEqualToString:@""]) {
                          //获取创建索引的语句
                          [sqls addObject:indexSQL];
                     }
                }
            }
        }
        
        //数据库升级行为
        for (int begin = dbVersion; begin <= _version - 1 ; begin++) {
            int end = begin + 1;
            
            //进行表更新操作
            for (Class tableProtocolClass in _tables) {
                //进行数据库层的初始化操作
                if ([tableProtocolClass conformsToProtocol:@protocol(OPFTableProtocol)]) {
                    NSArray* tableSQLs = [tableProtocolClass  performSelector:@selector(updateTable:toVersion:) withObject:@(begin) withObject:@(end)];
                    [sqls addObjectsFromArray:tableSQLs];
                }
            }
        }
         
         //更新Version版本号
         NSString* updateVersionSQL = [NSString stringWithFormat:UPDATE_VERSION,_version];
         [sqls addObject:updateVersionSQL];
         
         [_dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
              for (NSString* sql in sqls) {
                   BOOL update =   [db executeUpdate:sql];
                   if (!update) {
                        [self p_strictMode:[db lastError]];
                        *rollback = YES;
                        break;
                   }
              }
         }];
    });
     
}

#pragma 同步更新方法,单个SQL
/**
 *  同步执行一个是更新操作
 *
 *  @param sql SQL语句
 *
 *  @return 返回是否执行成功
 */
-(BOOL)syncExecuteUpdate:(NSString*)sql{
    
    [self p_checkMainThread];
    

    __block BOOL success = NO;
         [self p_dbWrite:^(FMDatabase *db, BOOL *rollback) {
                   success = [db executeUpdate:sql];
              
                   if (!success) {
                        [self p_strictMode:[db lastError]];
                        *rollback = YES;
                   }
              } sql:sql];
    return success;
}

/**
 *  同步执行一个是更新操作
 *
 *  @param sql  SQL语句
 *  @param args 参数列表
 *
 *  @return 返回是否执行成功
 */
-(BOOL)syncExecuteUpdate:(NSString*)sql withDictionaryArgs:(NSDictionary*)args{
    [self p_checkMainThread];
    __block BOOL success = NO;
         [self p_dbWrite:^(FMDatabase *db, BOOL *rollback) {
              success = [db executeUpdate:sql withParameterDictionary:args];
              if (!success) {
                   [self p_strictMode:[db lastError]];
                   *rollback = YES;
              }
         } sql:sql];
    return success;
}

/**
 *  同步执行一个是更新操作
 *
 *  @param sql  SQL语句
 *  @param args 参数列表
 *
 *  @return 返回是否执行成功
 */
-(BOOL)syncExecuteUpdate:(NSString*)sql withArrayArgs:(NSArray*)args{
    [self p_checkMainThread];
    __block BOOL success = NO;
         [self p_dbWrite:^(FMDatabase *db, BOOL *rollback) {
              success = [db executeUpdate:sql withArgumentsInArray:args];
              if (!success) {
                   [self p_strictMode:[db lastError]];
                   *rollback = YES;
              }
         } sql:sql];
    return success;
}

#pragma 同步更新方法,多个SQL
/**
 *  执行一系列的SQL操作
 *
 *  @param sqls SQL语句集合
 *
 *  @return 返回成功或失败，只有所有的成功才会成功
 */
-(BOOL)syncExecuteUpdates:(NSArray *)sqls{
    [self p_checkMainThread];
    
    __block BOOL success = NO;
         [self p_dbWrite:^(FMDatabase *db, BOOL *rollback) {
              for (NSString* sql in sqls) {
                   BOOL success = [db executeUpdate:sql];
                   if (!success) {
                        [self p_strictMode:[db lastError]];
                        success = NO;
                        *rollback = YES;
                        return ;
                   }
              }
              success = YES;
         } sql:[sqls description]];
    return success;
}

/**
 *  执行一系列的SQL操作
 *
 *  @param sqls SQL语句集合
 *  @param args 对应的参数列表，有多少个SQL，就必须有多少个参数列表
 *
 *  @return 返回成功或失败，只有所有的成功才会成功
 */
-(BOOL)syncExecuteUpdates:(NSArray *)sqls withDictionaryArgs:(NSArray*)args{
    [self p_checkMainThread];
    
    __block BOOL success = NO;
         [self p_dbWrite:^(FMDatabase *db, BOOL *rollback) {
              for (int i =0;i<sqls.count;i++) {
                   NSString* sql  = sqls[i];
                   NSDictionary* params = args[i];
                   BOOL success = [db executeUpdate:sql withParameterDictionary:params];
                   if (!success) {
                        [self p_strictMode:[db lastError]];
                        success = NO;
                        *rollback = YES;
                        return ;
                   }
              }
              success = YES;
         } sql:[sqls description]];
    return success;
}

/**
 *  将BLOCK里的数据库操作，全部归纳到一个事务中去
 *
 *  @param dbBlock BLOC行为
 *
 *  @return 返回是否成功
 */
-(void)syncInTransaction:(void(^)(BOOL *rollback))dbBlock{
//     NSDate* tmpStartData = [NSDate date];
     NSString* currentThreadName = [NSThread currentThread].name;
     BOOL inTransaction = [DB_THREAD_NAME isEqualToString:currentThreadName];
     
     if (!inTransaction) {
          if (!_dbQueue) {
               return;
          }
          dispatch_sync(_threadQueue, ^{
               [[NSThread currentThread] setName:DB_THREAD_NAME];

               [_dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
                    dbBlock(&*rollback);
               }];
               [[NSThread currentThread] setName:nil];

          });
     }else{
          [_dbQueue inWrtite:^(FMDatabase *db, BOOL *rollback) {
               dbBlock(&*rollback);
          }];
     }
//     double deltaTime = [[NSDate date] timeIntervalSinceDate:tmpStartData];
//     NSLog(@"数据库耗时 %f", deltaTime);


}

/**
 *  执行一系列的SQL操作
 *
 *  @param sqls SQL语句集合
 *  @param args 对应的参数列表，有多少个SQL，就必须有多少个参数列表
 *
 *  @return 返回成功或失败，只有所有的成功才会成功
 */
-(BOOL)syncExecuteUpdates:(NSArray *)sqls withArrayArgs:(NSArray*)args{
    [self p_checkMainThread];
    
    __block BOOL success = NO;
     
     
         [self p_dbWrite:^(FMDatabase *db, BOOL *rollback) {
              for (int i =0;i<sqls.count;i++) {
                   NSString* sql  = sqls[i];
                   NSArray* params = args[i];
                   BOOL success = [db executeUpdate:sql withArgumentsInArray:params];
                   if (!success) {
                        [self p_strictMode:[db lastError]];
                        success = NO;
                        *rollback = YES;
                        return ;
                   }
              }
              success = YES;
         } sql:[sqls description]];

    return success;
}

#pragma 同步查询
/**
 *  同步执行一个查询
 *
 *  @param sql 查询SQL
 *
 *  @return 返回查询结果，结果为NSArray，Array里面为NSDictionary
 */
-(NSArray*)syncExecuteQuery:(NSString*)sql{
    [self p_checkMainThread];
    
    __block NSMutableArray *results = [[NSMutableArray alloc] init];
     [self p_dbRead:^(FMDatabase *db) {
          FMResultSet * rs = [db executeQuery:sql];
          while (rs.next) {
               NSDictionary* data = [self p_rsToNSDictionary:rs];
               if (data) {
                    [results addObject:data];
               }
          }
          if ([db lastError]) {
               [self p_strictMode:[db lastError]];
          }
          if (rs) {
               [rs close];
          }
     } sql:sql];
    return results;
}

/**
 *  同步执行一个查询
 *
 *  @param sql  查询SQL
 *  @param args 参数列表
 *
 *  @return 返回查询结果 ，结果为NSArray，Array里面为NSDictionary，是数据库的键值对
 */
-(NSArray*)syncExecuteQuery:(NSString*)sql withDictionaryArgs:(NSDictionary*)args{
    
    [self p_checkMainThread];

    __block NSMutableArray *results = [[NSMutableArray alloc] init];
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withParameterDictionary:args];
               while (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    if (data) {
                         [results addObject:data];
                    }
               }
          if ([db lastError]) {
               [self p_strictMode:[db lastError]];
          }
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return results;
}

/**
 *  同步执行一个查询
 *
 *  @param sql  查询SQL
 *  @param args 参数列表
 *
 *  @return 返回查询结果 ，结果为NSArray,Array里面为NSDictionary，是数据库的键值对
 */
-(NSArray*)syncExecuteQuery:(NSString*)sql withArrayArgs:(NSArray*)args{
    [self p_checkMainThread];
    
    __block NSMutableArray *results = [[NSMutableArray alloc] init];
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withArgumentsInArray:args];
               while (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    if (data) {
                         [results addObject:data];
                    }
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return results;
}


#pragma 同步查询,单例
/**
 *  单例查询，当SQL语句仅返回一条数据时使用此方法
 *
 *  @param sql 查询SQL
 *
 *  @return 返回NSDictionary
 */
-(NSDictionary*)syncSingleExecuteQuery:(NSString*)sql{
    [self p_checkMainThread];
    
    __block NSDictionary* result = nil;
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql];
               if (rs.next) {
                    result = [self p_rsToNSDictionary:rs];
               }
         [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return result;
}

/**
 *  单例查询，当SQL语句仅返回一条数据时使用此方法
 *
 *  @param sql  SQL语句
 *  @param args 参数列表
 *
 *  @return 返回一个NSDictionary
 */
-(NSDictionary*)syncSingleExecuteQuery:(NSString*)sql withDictionaryArgs:(NSDictionary*)args{
    [self p_checkMainThread];

    __block NSDictionary* result = nil;
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withParameterDictionary:args];
               if (rs.next) {
                    result = [self p_rsToNSDictionary:rs];
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return result;
}

/**
 *  同步单例查询，当SQL语句仅返回一条数据时使用此方法
 *
 *  @param sql  SQL语句
 *  @param args 参数列表
 *
 *  @return 返回查询结果 ，结果为NSDictionary
 */
-(NSDictionary*)syncSingleExecuteQuery:(NSString*)sql withArrayArgs:(NSArray*)args{
    [self p_checkMainThread];
    
    __block NSDictionary* result = nil;
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withArgumentsInArray:args];
               if (rs.next) {
                    result = [self p_rsToNSDictionary:rs];
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return result;
}

#pragma 同步查询,返回对象
/**
 *  同步查询，返回Model集合
 *
 *  @param sql            SQL语句
 *  @param convertBlock 用户提供NSDictionary到对象的整合block
 *
 *  @return 返回一个数组，数组中为对象
 */
-(NSArray*)syncExecuteQuery:(NSString*)sql convertBlock:(id(^)(NSDictionary * result))convertBlock{
    [self p_checkMainThread];
    
    NSMutableArray* results = [[NSMutableArray alloc] init];
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql];
               while (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    if (data) {
                         [results addObject:convertBlock(data)];
                    }
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return results;
}


/**
 *  同步查询，返回Model集合
 *
 *  @param sql          SQL语句
 *  @param args         参数列表
 *  @param convertBlock 用户提供NSDictionary到对象的整合block
 *
 *  @return 返回一个数组，数组中为对象
 */
-(NSArray*)syncExecuteQuery:(NSString *)sql withDictionaryArgs:(NSDictionary*)args convertBlock:(id (^)(NSDictionary* result))convertBlock{
    [self p_checkMainThread];

    NSMutableArray* results = [[NSMutableArray alloc] init];
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withParameterDictionary:args];
               while (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    if (data) {
                         [results addObject:convertBlock(data)];
                    }
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return results;
    
}

/**
 *  同步查询，返回Model集合
 *
 *  @param sql          SQL语句
 *  @param args         参数列表
 *  @param convertBlock 用户提供NSDictionary到对象的整合block
 *
 *  @return 返回一个数组，数组中为对象
 */
-(NSArray*)syncExecuteQuery:(NSString *)sql withArraysArgs:(NSArray*)args convertBlock:(id (^)(NSDictionary* result))convertBlock{
    NSMutableArray* results = [[NSMutableArray alloc] init];
    [self p_checkMainThread];
    
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withArgumentsInArray:args];
               while (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    if (data) {
                         [results addObject:convertBlock(data)];
                    }
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return results;
}


#pragma 同步查询,对象且单例
/**
 *  同步查询，返回Model集合
 *
 *  @param sql            SQL语句
 *  @param convertBlock 用户提供NSDictionary到对象的整合block
 *
 *  @return 返回一个对象
 */
-(id)syncSingleExecuteQuery:(NSString*)sql convertBlock:(id(^)(NSDictionary * result))convertBlock{
    [self p_checkMainThread];
    
   __block id result = nil;
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql];
               if (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    result = convertBlock(data);
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return result;
}


/**
 *  同步查询，返回Model集合
 *
 *  @param sql          SQL语句
 *  @param args         参数列表
 *  @param convertBlock 用户提供NSDictionary到对象的整合block
 *
 *  @return 返返回一个对象
 */
-(id)syncSingleExecuteQuery:(NSString *)sql withDictionaryArgs:(NSDictionary*)args convertBlock:(id (^)(NSDictionary* result))convertBlock{
    [self p_checkMainThread];

    __block id result = nil;
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withParameterDictionary:args];
               if (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    result = convertBlock(data);
               }
          [self p_strictMode:[db lastError]];
               if (rs) {
                    [rs close];
               }
     } sql:sql];
    return result;
}

/**
 *  同步查询，返回Model集合
 *
 *  @param sql          SQL语句
 *  @param args         参数列表
 *  @param convertBlock 用户提供NSDictionary到对象的整合block
 *
 *  @return 返回一个对象
 */
-(id)syncSingleExecuteQuery:(NSString *)sql withArraysArgs:(NSArray*)args convertBlock:(id (^)(NSDictionary* result))convertBlock{
    [self p_checkMainThread];
    __block id result = nil;
     [self p_dbRead:^(FMDatabase *db) {
               FMResultSet * rs = [db executeQuery:sql withArgumentsInArray:args];
               if (rs.next) {
                    NSDictionary* data = [self p_rsToNSDictionary:rs];
                    result = convertBlock(data);
               }
               if (rs) {
                    [rs close];
               }
          [self p_strictMode:[db lastError]];

     } sql:sql];
    return result;
    
}

/**
 *  查询数据库中某个表是否存在
 *
 *  @param tableName 表名
 *
 *  @return 返回结果
 */
-(BOOL)syncQueryTableExists:(NSString*)tableName{
    [self p_checkMainThread];
     __block BOOL exists = NO;
    NSString* sql = @"SELECT * FROM sqlite_master WHERE type='table' AND name=? COLLATE NOCASE";

     [self p_dbRead:^(FMDatabase *db) {
          FMResultSet *rs  = [db executeQuery:sql withArgumentsInArray:@[tableName]];
          if (rs.next) {
               exists = YES;
          }
          if (rs) {
               [rs close];
          }
     } sql:sql];
     return exists;
}

/**
 *  异步查询表是否存在
 *
 *  @param tableName   表名
 *  @param resultBlock 回调
 *
 */
-(void)syncQueryTableExists:(NSString*)tableName resultBlock:(void(^)(BOOL success))resultBlock{
    if (!resultBlock) {
        return;
    }
    NSString* sql = @"SELECT count(*) FROM sqlite_master WHERE type='table' AND name=? ";

     [self p_dbRead:^(FMDatabase *db) {
          FMResultSet *rs  = [db executeQuery:sql withArgumentsInArray:@[tableName]];
          if (rs.next) {
               resultBlock(YES);
          }else{
               resultBlock(NO);
          }
          if (rs) {
               [rs close];
          }

     } sql:sql];
}

/**
 *  返回最后更新的ROW ID
 *
 */
-(long long int)lastInsertRowId{
     
     __block long long int rowId;
     [self p_dbRead:^(FMDatabase *db) {
          rowId = [db lastInsertRowId];
     } sql:@"lastInsertRowId"];
     
     return rowId;
}

#pragma FMResultSet 转 NSDictionary

/**
 *  将RS转为Dictionary
 *
 *  @param rs RS
 *
 *  @return 返回NSDictionary对象
 */
-(NSDictionary*)p_rsToNSDictionary:(FMResultSet*)rs{
    NSMutableDictionary * results = [[NSMutableDictionary alloc] init];
    
    NSMutableDictionary *keys = rs.columnNameToIndexMap;
    for (NSString* name in keys.allKeys) {
        id value = [rs objectForColumnName:name];
        if (value) {
            [results setObject:value forKey:name];
        }
    }
    return results;
}

/**
 *  检查是否在主线程进行操作
 */
-(void)p_checkMainThread{
    BOOL isMainThread = [NSThread isMainThread];
    if (isMainThread) {
        [NSException raise:@"db main thread exception" format:@"DB Actions Not Allow in Main Thread"];
    }
}

-(void)p_dbWrite:(void (^)(FMDatabase *db, BOOL *rollback))block sql:(NSString*)sql{
    UInt64 begin = [[NSDate date] timeIntervalSince1970] * 1000;
     NSString* currentThreadName = [NSThread currentThread].name;
     BOOL inTransaction = [DB_THREAD_NAME isEqualToString:currentThreadName];

     if (inTransaction) {
          [_dbQueue inWrtite:^(FMDatabase *db, BOOL *rollback) {
               block(db,&*rollback);
          }];
     }else{
          if (!_dbQueue) {
               return;
          }
          dispatch_sync(_threadQueue, ^{
               [[NSThread currentThread] setName:DB_THREAD_NAME];
               [_dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
                    block(db,&*rollback);
               }];
               [[NSThread currentThread] setName:nil];
          });
     }
    
    UInt64 end  = [[NSDate date] timeIntervalSince1970] * 1000;

    //如果一个网络请求大于10S，则进行日志记录
    if (end - begin > DB_MONITOR_TIME) {
        NSString* text = [NSString stringWithFormat:@"DB MONITOR: time:%llu SQL:%@",(end - begin),sql];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"WOP_DD_LOG" object:nil userInfo:@{
                                                                                                       @"text":text
                                                                                                       }];
    }
}

-(void)p_dbRead:(void (^)(FMDatabase *db))block sql:(NSString*)sql{
    UInt64 begin = [[NSDate date] timeIntervalSince1970] * 1000;

     NSString* currentThreadName = [NSThread currentThread].name;
     BOOL inTransaction = [DB_THREAD_NAME isEqualToString:currentThreadName];

     if (inTransaction) {
          [_dbQueue inReader:^(FMDatabase *db) {
               block(db);
          }];
     }else{
          if (!_threadQueue) {
               return;
          }
          dispatch_sync(_threadQueue, ^{
               [[NSThread currentThread] setName:DB_THREAD_NAME];
               [_dbQueue inDatabase:^(FMDatabase *db) {
                    block(db);
               }];
               [[NSThread currentThread] setName:nil];
          });
     }
    
    UInt64 end  = [[NSDate date] timeIntervalSince1970] * 1000;

    //如果一个网络请求大于10S，则进行日志记录
    if (end - begin > DB_MONITOR_TIME) {
        NSString* text = [NSString stringWithFormat:@"DB MONITOR: time:%llu SQL:%@",(end - begin),sql];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"WOP_DD_LOG" object:nil userInfo:@{
                                                                                                       @"text":text
                                                                                                       }];
    }
     
}

/**
 *  严格模式的行为
 */
-(void)p_strictMode:(NSError*)error{
     if (error.code ==0 || error.code == 100) {
          return;
     }
     NSString* errorString = [NSString stringWithFormat:@"%@:%@",@"StrictMode DB Error:",error.domain];
     if (_strictMode) {
          [NSException raise:@"db Error" format:@"StrictMode DB Error:%@",errorString];
     }
     
     //数据库加密或版本不对
     if ([error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"file is encrypted or is not a database"]) {
          NSLog(@"HELLO");
          [[NSNotificationCenter defaultCenter] postNotificationName:@"Database_Encrypt_Error" object:nil];
          return;
     }
    
    DDLogDebug(@"%@",errorString);
    
#ifdef DEBUG
     [NSException raise:@"db Error" format:@"DeBug DB Error:%@",errorString];
#endif
}

-(void)dealloc{
//     NSLog(@"数据库销毁了啊");
     _threadQueue = nil;
     _dbQueue = nil;
}

@end
